﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Practices.Unity;
using Microsoft.Practices.ServiceLocation;
using SkeletonNET.Crud.Repository;
using SkeletonNET.Base.Crud.CrudManager;
using System.Linq.Expressions;
using SkeletonNET.Base.Crud.UnitOfWork;
using System.Diagnostics;

namespace SkeletonNET.Data.Tests
{
    [TestClass]
    public class CompiledRepositoryQueryTests
    {
        [TestInitialize]
        public void Initialize()
        {
            var container = new UnityContainer();
            ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
            ServiceLocator.Current.GetInstance<IUnityContainer>()
                .RegisterType(typeof(IRepository<>), typeof(Repository<>))
                .RegisterType(typeof(ICrudManager<>), typeof(CrudManager<>))
                .RegisterType<ICrudManager<TestEntity>, TestCrudManager>()
                .RegisterType<IUnitOfWork, FakeDbContext>();
        }

        [TestMethod]
        public void TestCompiledRepositoryQuery()
        {
            // Insert some data
            var manager = (TestCrudManager)ServiceLocator.Current.GetInstance<ICrudManager<TestEntity>>();

            for (int i = 0; i < 1000000; i++)
                manager.Insert(new TestEntity() { ID = 1 });

            Stopwatch watch = Stopwatch.StartNew();
            // Test uncompiled query
            manager.Test(999);
            Debug.WriteLine("Uncompiled: " + watch.ElapsedMilliseconds);

            watch = Stopwatch.StartNew();
            // Test compiled query
            manager.TestCompiled(999);
            Debug.WriteLine("Compiled: " + watch.ElapsedMilliseconds);
        }

        public class TestCrudManager : CrudManager<TestEntity>
        {
            private static Expression<Func<IRepository<TestEntity>, int, TestEntity>> GetByIDTest = (repository, id)
                => repository.GetQuery().Where(x => x.ID == id).FirstOrDefault();
            private static Func<IRepository<TestEntity>, int, TestEntity> GetByIDTestCompiled = GetByIDTest.Compile();

            public TestEntity TestCompiled(int id)
            {
                var repo = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
                return GetByIDTestCompiled(repo, 1);
            }

            public TestEntity Test(int id)
            {
                var repo = ServiceLocator.Current.GetInstance<IRepository<TestEntity>>();
                return repo.GetQuery()
                    .Where(x => x.ID == id)
                    .FirstOrDefault();
            }
        }
    }
}